<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="O9QGY" id="O9QGY"><span data-lake-id="uf4e26630" id="uf4e26630">典型回答</span></h1>
  <p data-lake-id="ub0c6c160" id="ub0c6c160"><br></p>
  <p data-lake-id="uc6b580ff" id="uc6b580ff"><span data-lake-id="ud15be7ef" id="ud15be7ef">Kafka消息只消费一次，这个需要从多方面回答，既包含Kafka自身的机制，也需要考虑客户端自己的重复处理。</span></p>
  <p data-lake-id="u374a3b04" id="u374a3b04"><span data-lake-id="u831c45dc" id="u831c45dc">​</span><br></p>
  <p data-lake-id="u067b3986" id="u067b3986"><span data-lake-id="u4e2def8e" id="u4e2def8e">可以从以下几个方面回答：</span></p>
  <p data-lake-id="u8f5d26c2" id="u8f5d26c2"><span data-lake-id="uc8aa34fb" id="uc8aa34fb">​</span><br></p>
  <p data-lake-id="u894b8721" id="u894b8721"><span data-lake-id="u9b089440" id="u9b089440">首先，在Kafka中，每个消费者都必须加入至少一个</span><strong><span data-lake-id="u6434b33e" id="u6434b33e">消费者组</span></strong><span data-lake-id="ucfe6872f" id="ucfe6872f">。同一个消费者组内的消费者可以共享消费者的负载。因此，如果一个消息被消费组中的任何一个消费者消费了，那么其他消费者就不会再收到这个消息了。</span></p>
  <p data-lake-id="ubc6b61e2" id="ubc6b61e2"><span data-lake-id="u1b1d9cc5" id="u1b1d9cc5">​</span><br></p>
  <p data-lake-id="ua1f724e2" id="ua1f724e2"><span data-lake-id="u84f663f3" id="u84f663f3">另外，消费者可以通过</span><strong><span data-lake-id="uad5c3ebc" id="uad5c3ebc">手动提交消费位移</span></strong><span data-lake-id="ucf9da56b" id="ucf9da56b">来控制消息的消费情况。通过手动提交位移，消费者可以跟踪自己已经消费的消息，确保不会重复消费同一消息。</span></p>
  <p data-lake-id="u2c969252" id="u2c969252"><span data-lake-id="ucede7ccf" id="ucede7ccf">​</span><br></p>
  <p data-lake-id="u66d8325c" id="u66d8325c"><span data-lake-id="u6f860394" id="u6f860394">还有就是客户端自己可以做一些</span><strong><span data-lake-id="u752701c0" id="u752701c0">幂等机制</span></strong><span data-lake-id="u8e2610e6" id="u8e2610e6">，防止消息的重复消费。</span></p>
  <p data-lake-id="u79e96a3c" id="u79e96a3c"><br></p>
  <p data-lake-id="u64382e98" id="u64382e98"><br></p>
  <p data-lake-id="ufd47c846" id="ufd47c846"><span data-lake-id="ue5d38bdc" id="ue5d38bdc">另外可以借助Kafka的</span><strong><span data-lake-id="u5dd99995" id="u5dd99995">Exactly-once消费语义</span></strong><span data-lake-id="u7c3825df" id="u7c3825df">，其实就是引入了事务，消费者使用事务来保证消息的消费和位移提交是原子的，而生产者可以使用事务来保证消息的生产和位移提交是原子的。Exactly-once消费语义则解决了重复问题，但需要更复杂的设置和配置。</span></p>
  <p data-lake-id="u7f32edce" id="u7f32edce"><span data-lake-id="ua8486726" id="ua8486726">​</span><br></p>
  <h1 data-lake-id="FMJEi" id="FMJEi"><span data-lake-id="u0b159a33" id="u0b159a33">扩展知识</span></h1>
  <p data-lake-id="u4bc3d042" id="u4bc3d042"><br></p>
  <h3 data-lake-id="XwLLc" id="XwLLc"><span data-lake-id="uaff9bf6f" id="uaff9bf6f">Kafka的三种消息传递语义</span></h3>
  <p data-lake-id="u1a61ac02" id="u1a61ac02"><br></p>
  <p data-lake-id="uc2980c49" id="uc2980c49"><span data-lake-id="uabe382d3" id="uabe382d3">在Kafka中，有三种常见的消息传递语义：At-least-once、At-most-once和Exactly-once。其中At-least-once和Exactly-once是最常用的。</span></p>
  <p data-lake-id="uceb95515" id="uceb95515"><span data-lake-id="u13b8866b" id="u13b8866b">​</span><br></p>
  <h3 data-lake-id="GfTNM" id="GfTNM"><span data-lake-id="ueea37f59" id="ueea37f59">At-least-once消费语义</span></h3>
  <p data-lake-id="u3cca0e73" id="u3cca0e73"><br></p>
  <p data-lake-id="uc2a54f82" id="uc2a54f82"><strong><span data-lake-id="u08a22694" id="u08a22694">At-least-once消费语义意味着消费者至少消费一次消息，但可能会重复消费同一消息</span></strong><span data-lake-id="u24f1010c" id="u24f1010c">。在At-least-once语义中，当消费者从Kafka服务器读取消息时，消息的偏移量会被记录下来。一旦消息被成功处理，消费者会将位移提交回Kafka服务器。如果消息处理失败，消费者不会提交位移。这意味着该消息将在下一次重试时再次被消费。</span></p>
  <p data-lake-id="u578bc284" id="u578bc284"><span data-lake-id="ub5a23863" id="ub5a23863">​</span><br></p>
  <p data-lake-id="uc7da9198" id="uc7da9198"><strong><span data-lake-id="u90a191a8" id="u90a191a8">At-least-once语义通常用于实时数据处理或消费者不能容忍数据丢失的场景，例如金融交易或电信信令。</span></strong></p>
  <p data-lake-id="u05c9b9d1" id="u05c9b9d1"><span data-lake-id="ua6556b85" id="ua6556b85">​</span><br></p>
  <h3 data-lake-id="OgeS4" id="OgeS4"><span data-lake-id="u7dea041d" id="u7dea041d">Exactly-once消费语义</span></h3>
  <p data-lake-id="ueaa87a4d" id="ueaa87a4d"><br></p>
  <p data-lake-id="u517b4606" id="u517b4606"><span data-lake-id="ud4e9aef0" id="ud4e9aef0">Exactly-once消费语义意味着每个消息仅被消费一次，且不会被重复消费。在Exactly-once语义中，Kafka保证消息只被处理一次，同时保持消息的顺序性。为了实现Exactly-once语义，Kafka引入了一个新的概念：事务。</span></p>
  <p data-lake-id="u81068066" id="u81068066"><span data-lake-id="u8516e01d" id="u8516e01d">​</span><br></p>
  <p data-lake-id="u50f449a1" id="u50f449a1"><span data-lake-id="u3b37b467" id="u3b37b467">事务是一系列的读写操作，这些操作要么全部成功，要么全部失败。在Kafka中，生产者和消费者都可以使用事务，以保证消息的Exactly-once语义。具体来说，消费者可以使用事务来保证消息的消费和位移提交是原子的，而生产者可以使用事务来保证消息的生产和位移提交是原子的。</span></p>
  <p data-lake-id="u0201dfb2" id="u0201dfb2"><span data-lake-id="ua30e5398" id="ua30e5398">​</span><br></p>
  <p data-lake-id="ud1025cab" id="ud1025cab"><span data-lake-id="u6e57889b" id="u6e57889b">在Kafka 0.11版本之前，实现Exactly-once语义需要一些特殊的配置和设置。但是，在Kafka 0.11版本之后，Kafka提供了原生的Exactly-once支持，使得实现Exactly-once变得更加简单和可靠。</span></p>
  <p data-lake-id="u4b414d49" id="u4b414d49"><span data-lake-id="u6cd9f81b" id="u6cd9f81b">​</span><br></p>
  <p data-lake-id="u6a34cb67" id="u6a34cb67"><span data-lake-id="udcab5a70" id="udcab5a70">总之，At-least-once消费语义保证了数据的可靠性，但可能会导致数据重复。而Exactly-once消费语义则解决了重复问题，但需要更复杂的设置和配置。选择哪种消费语义取决于业务需求和数据可靠性要求。</span></p>
 </body>
</html>